﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace CSharpProj.MyExpression
{
    public class DbExpressionVisitor : ExpressionVisitor
    {
        StringBuilder _sb = new StringBuilder();

        #region 表名生成管理

        private int _tableIndex;

        /// <summary>
        /// 获取新的查询别名
        /// </summary>
        public string NewAlias
        {
            get { return "t" + _tableIndex++; }
        }

        #endregion

        private Dictionary<string, ColumnExpression> _lastColumns = new Dictionary<string, ColumnExpression>();

        public override System.Linq.Expressions.Expression Visit(System.Linq.Expressions.Expression exp)
        {
            if (exp == null)
            {
                return null;
            }

            switch ((DbExpressionType)exp.NodeType)
            {
                case DbExpressionType.Select:
                case DbExpressionType.Table:
                case DbExpressionType.Join:
                case DbExpressionType.Query:
                    return this.VisitQuery((QueryExpression)exp);
                case DbExpressionType.Column:
                    return this.VisitColumn((ColumnExpression)exp);
            }

            return base.Visit(exp);
        }
        public Expression VisitQuery(QueryExpression exp)
        {
            switch (exp.ExpressionType)
            {
                case DbExpressionType.Select: this.VisitSelect((SelectExpression)exp); break;
                //case DbExpressionType.Table: this.VisitTable((TableExpression)exp); break;
                //case DbExpressionType.Join: this.VisitSource((JoinExpression)exp); break;
            }

            return exp;
        }

        public Expression VisitColumn(ColumnExpression column)
        {
            var value = column.Value;
            switch (value.NodeType)
            {
                case ExpressionType.MemberAccess:
                    if (!string.IsNullOrEmpty(column.SelectAlias))
                        _sb.AppendFormat("[{0}].", column.SelectAlias);

                    var member = ((MemberExpression)value).Member;
                    if (member.Name == column.ColumnName)
                        _sb.AppendFormat("[{0}]", column.ColumnName);
                    else
                        _sb.AppendFormat("[{0}] As [{1}]", member.Name, column.ColumnName);
                    break;
                default:
                    this.Visit(column.Value);
                    _sb.AppendFormat(" As [{0}]", column.ColumnName);
                    break;
            }

            return column;
        }


        public Expression VisitSelect(SelectExpression select)
        {
            _sb.Append("SELECT ");
            int index = 0;
            foreach (var column in select.Columns)
            {
                if (index++ > 0) _sb.Append(", ");
                this.VisitColumn(column);
            }

            if (select.From != null)
            {
                _sb.Append(" FROM ");
                if (!(select.From is TableExpression)) _sb.Append("(");
                this.Visit(select.From);
                if (!(select.From is TableExpression)) _sb.Append(")");
            }
            _sb.AppendFormat(" AS {0} ", select.Alias);

            return select;
        }


        protected override Expression VisitParameter(ParameterExpression param)
        {
            //如果缓存中没有任何列
            if (_lastColumns.Count == 0) return base.VisitParameter(param);

            var alias = this.NewAlias;

            //根据_lastColumns中生成newColumns,Value = Expression.Constant(oldColumn)也就是对oldColumn的一个引用
            var newColumns = _lastColumns.Values.Select(oldColumn =>
                    new ColumnExpression(oldColumn.Type,
                    Expression.Constant(oldColumn),
                    alias,
                    oldColumn.ColumnName,
                    oldColumn.Index)).ToList();

            //将生成的新列赋值给缓存
            _lastColumns = newColumns.ToDictionary(x => x.ColumnName);

            return new SelectExpression(param.Type, alias, newColumns.AsReadOnly(), null);
        }

        protected override Expression VisitConstant(ConstantExpression constant)
        {
            var queryable = constant.Value as IQueryable;
            if (queryable != null)
            {
                //TableAttribute用来描述类对应的数据库表信息
                var table = (TableAttribute)queryable.ElementType.GetCustomAttributes(typeof(TableAttribute), false).FirstOrDefault();
                //如果没有该特性，直接使用类名作为表名
                var tableName = table == null ? queryable.ElementType.Name : table.Name;

                //生成TableExpression,并将其Columns属性缓存
                var tableExp = new TableExpression(queryable.ElementType, string.Empty, tableName);
                _lastColumns = tableExp.Columns.ToDictionary(x => x.ColumnName);

                return tableExp;
            }

            return base.VisitConstant(constant);
        }
    }
}
